home *** CD-ROM | disk | FTP | other *** search
/ Windows Expert / Windows Expert.iso / windownt / tusrc.zip / SRC / COMM.C < prev    next >
C/C++ Source or Header  |  1993-09-18  |  6KB  |  249 lines

  1. /* comm -- compare two sorted files line by line.
  2.    Copyright (C) 1986, 1990, 1991 Free Software Foundation, Inc.
  3.  
  4.    This program is free software; you can redistribute it and/or modify
  5.    it under the terms of the GNU General Public License as published by
  6.    the Free Software Foundation; either version 2, or (at your option)
  7.    any later version.
  8.  
  9.    This program is distributed in the hope that it will be useful,
  10.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  11.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12.    GNU General Public License for more details.
  13.  
  14.    You should have received a copy of the GNU General Public License
  15.    along with this program; if not, write to the Free Software
  16.    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
  17.  
  18. /* Written by Richard Stallman and David MacKenzie. */
  19.  
  20. #include <stdio.h>
  21. #include "../lib/getopt.h"
  22. #include <sys/types.h>
  23. #include "system.h"
  24. #include "../lib/linebuffer.h"
  25. #include "version.h"
  26.  
  27. // #define min(x, y) ((x) < (y) ? (x) : (y))
  28.  
  29. /* The name this program was run with. */
  30. char *program_name;
  31.  
  32. /* If nonzero, print lines that are found only in file 1. */
  33. static int only_file_1;
  34.  
  35. /* If nonzero, print lines that are found only in file 2. */
  36. static int only_file_2;
  37.  
  38. /* If nonzero, print lines that are found in both files. */
  39. static int both;
  40.  
  41. /* If non-zero, display usage information and exit.  */
  42. static int flag_help;
  43.  
  44. /* If non-zero, print the version on standard error.  */
  45. static int flag_version;
  46.  
  47. static struct option const long_options[] =
  48. {
  49.   {"help", no_argument, &flag_help, 1},
  50.   {"version", no_argument, &flag_version, 1},
  51.   {0, 0, 0, 0}
  52. };
  53.  
  54. void error ();
  55. static int compare_files ();
  56. static void writeline ();
  57. static void usage ();
  58.  
  59. void
  60. main (argc, argv)
  61.      int argc;
  62.      char *argv[];
  63. {
  64.   int c;
  65.  
  66.   program_name = argv[0];
  67.  
  68.   only_file_1 = 1;
  69.   only_file_2 = 1;
  70.   both = 1;
  71.  
  72.   while ((c = getopt_long (argc, argv, "123", long_options, (int *) 0)) != EOF)
  73.     switch (c)
  74.       {
  75.       case 0:
  76.     break;
  77.  
  78.       case '1':
  79.     only_file_1 = 0;
  80.     break;
  81.  
  82.       case '2':
  83.     only_file_2 = 0;
  84.     break;
  85.  
  86.       case '3':
  87.     both = 0;
  88.     break;
  89.  
  90.       default:
  91.     usage ();
  92.       }
  93.  
  94.   if (flag_version)
  95.     {
  96.       fprintf (stderr, "%s\n", version_string);
  97.       exit (0);
  98.     }
  99.  
  100.   if (flag_help)
  101.     usage ();
  102.  
  103.   if (optind + 2 != argc)
  104.     usage ();
  105.  
  106.   exit (compare_files (argv + optind));
  107. }
  108.  
  109. /* Compare INFILES[0] and INFILES[1].
  110.    If either is "-", use the standard input for that file.
  111.    Assume that each input file is sorted;
  112.    merge them and output the result.
  113.    Return 0 if successful, 1 if any errors occur. */
  114.  
  115. static int
  116. compare_files (infiles)
  117.      char **infiles;
  118. {
  119.   /* For each file, we have one linebuffer in lb1.  */
  120.   struct linebuffer lb1[2];
  121.  
  122.   /* thisline[i] points to the linebuffer holding the next available line
  123.      in file i, or is NULL if there are no lines left in that file.  */
  124.   struct linebuffer *thisline[2];
  125.  
  126.   /* streams[i] holds the input stream for file i.  */
  127.   FILE *streams[2];
  128.  
  129.   int i, ret = 0;
  130.  
  131.   /* Initialize the storage. */
  132.   for (i = 0; i < 2; i++)
  133.     {
  134.       initbuffer (&lb1[i]);
  135.       thisline[i] = &lb1[i];
  136.       streams[i] = strcmp (infiles[i], "-")
  137.     ? fopen (infiles[i], "r") : stdin;
  138.       if (!streams[i])
  139.     {
  140.       error (0, errno, "%s", infiles[i]);
  141.       return 1;
  142.     }
  143.  
  144.       thisline[i] = readline (thisline[i], streams[i]);
  145.     }
  146.  
  147.   while (thisline[0] || thisline[1])
  148.     {
  149.       int order;
  150.  
  151.       /* Compare the next available lines of the two files.  */
  152.  
  153.       if (!thisline[0])
  154.     order = 1;
  155.       else if (!thisline[1])
  156.     order = -1;
  157.       else
  158.     {
  159.       /* Cannot use bcmp -- it only returns a boolean value. */
  160.       order = memcmp (thisline[0]->buffer, thisline[1]->buffer,
  161.               min (thisline[0]->length, thisline[1]->length));
  162.       if (order == 0)
  163.         order = thisline[0]->length - thisline[1]->length;
  164.     }
  165.  
  166.       /* Output the line that is lesser. */
  167.       if (order == 0)
  168.     writeline (thisline[1], stdout, 3);
  169.       else if (order > 0)
  170.     writeline (thisline[1], stdout, 2);
  171.       else
  172.     writeline (thisline[0], stdout, 1);
  173.  
  174.       /* Step the file the line came from.
  175.      If the files match, step both files.  */
  176.       if (order >= 0)
  177.     thisline[1] = readline (thisline[1], streams[1]);
  178.       if (order <= 0)
  179.     thisline[0] = readline (thisline[0], streams[0]);
  180.     }
  181.  
  182.   /* Free all storage and close all input streams. */
  183.   for (i = 0; i < 2; i++)
  184.     {
  185.       free (lb1[i].buffer);
  186.       if (ferror (streams[i]) || fclose (streams[i]) == EOF)
  187.     {
  188.       error (0, errno, "%s", infiles[i]);
  189.       ret = 1;
  190.     }
  191.     }
  192.   if (ferror (stdout) || fclose (stdout) == EOF)
  193.     {
  194.       error (0, errno, "write error");
  195.       ret = 1;
  196.     }
  197.   return ret;
  198. }
  199.  
  200. /* Output the line in linebuffer LINE to stream STREAM
  201.    provided the switches say it should be output.
  202.    CLASS is 1 for a line found only in file 1,
  203.    2 for a line only in file 2, 3 for a line in both. */
  204.  
  205. static void
  206. writeline (line, stream, class)
  207.      struct linebuffer *line;
  208.      FILE *stream;
  209.      int class;
  210. {
  211.   switch (class)
  212.     {
  213.     case 1:
  214.       if (!only_file_1)
  215.     return;
  216.       break;
  217.  
  218.     case 2:
  219.       if (!only_file_2)
  220.     return;
  221.       /* Skip the tab stop for case 1, if we are printing case 1.  */
  222.       if (only_file_1)
  223.     putc ('\t', stream);
  224.       break;
  225.  
  226.     case 3:
  227.       if (!both)
  228.     return;
  229.       /* Skip the tab stop for case 1, if we are printing case 1.  */
  230.       if (only_file_1)
  231.     putc ('\t', stream);
  232.       /* Skip the tab stop for case 2, if we are printing case 2.  */
  233.       if (only_file_2)
  234.     putc ('\t', stream);
  235.       break;
  236.     }
  237.  
  238.   fwrite (line->buffer, sizeof (char), line->length, stream);
  239.   putc ('\n', stream);
  240. }
  241.  
  242. static void
  243. usage ()
  244. {
  245.   fprintf (stderr, "Usage: %s [-123] [--help] [--version] file1 file2\n",
  246.        program_name);
  247.   exit (1);
  248. }
  249.